package com.cskaoyan.controller;

import com.cskaoyan.aliyun.WdAliyunClient;
import com.cskaoyan.bean.data.RegisterData;
import com.cskaoyan.bean.vo.BaseRespVo;
import com.cskaoyan.config.SmsVerificationService;
import com.cskaoyan.model.MarketUser;
import com.cskaoyan.service.UserService;
import com.cskaoyan.util.MD5Util;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @Author Pudding
 * @Date 2024/6/13 23:20
 */
@RestController
@RequestMapping("wx/auth")
public class WxAuthController {
    @Autowired
    UserService userService;

    @Autowired
    WdAliyunClient wdAliyunClient;


    // 1. 用户登录
    @PostMapping("login")
    public BaseRespVo login(@RequestBody Map<String, String> map) {
        String username = map.get("username");
        String password = map.get("password");
        // 这里通过md5方式给密码进行加密，之后比较的是加密之后的密码
        String md5Password = MD5Util.getMd5(password);

        // 1. subject表示当前用户（基于Shiro的Session会话技术）
        Subject subject = SecurityUtils.getSubject();
        // 2. login(AuthenticationToken)：通过Realm(域)查询系统内的credentials → 密码的比对(传入的密码和系统内的credentials的比对) → isAuthenticated
        // 其中username用来给realm查询出来的credentials
        // 其中password用来和查询出来的credentials做比较，如果比较成功把isAuthenticated=true
        try {
            subject.login(new UsernamePasswordToken(username, md5Password));
        } catch (IncorrectCredentialsException e) {
            return BaseRespVo.fail("账号密码不对", 700);
        } catch (AuthenticationException e) {
            return BaseRespVo.fail("账号不存在", 700);
        }
        boolean authenticated = subject.isAuthenticated();

        // 登录成功
        if (authenticated) {
            // 在登录(认证)成功的情况下，可以获取用户信息，从realm中的doGetAuthenticationInfo方法中获取信息
            // 1. 取出realm中存的用户id
            Integer userId = (Integer) subject.getPrincipal();
            // 2. 根据userId查询对应的用户信息
            MarketUser marketUser = userService.findById(userId);

            // 3. 封装响应结果中的data
            HashMap<String, Object> data = new HashMap<>();
            // 3.1 data中token
            Serializable token = subject.getSession().getId();  //从当前 Subject 获取会话。从会话中获取其唯一标识符（ID）。将此 ID 存储在一个名为 token 的变量中，该变量可以被序列化
            // 3.2 data中的userInfo
            HashMap<String, String> userInfo = new HashMap<>();
            userInfo.put("avatarUrl", marketUser.getAvatar());
            userInfo.put("nickName", marketUser.getNickname());
            // 3.3 封装data数据
            //返回SessionId,小程序的其他请求就会携带这个SessionId过来，而前端请求头携带sessionId的key为X-CskaoyanMarket-Token
            data.put("token", token);
            data.put("userInfo", userInfo);

            return BaseRespVo.ok(data);
        }
        // 登录失败：未登录，请先登录
        return BaseRespVo.unAuthc();
    }


    // 2. 如果没有登录的话，会重定向到这个没有身份验证的地方
    @GetMapping("unAuthc")
    public BaseRespVo unAuthc() {
        return BaseRespVo.unAuthc();
    }

    @PostMapping("regCaptcha")
    public BaseRespVo regCaptcha(@RequestBody Map<String, String> map) {

        String mobile = map.get("mobile");
        String phonePattern = "^1[3456789]\\d{9}$";

        // 创建Pattern对象
        Pattern pattern = Pattern.compile(phonePattern);

        // 创建Matcher对象
        Matcher matcher = pattern.matcher(mobile);

        // 判断手机号是否合法
        if (matcher.matches()) {
            Random r = new Random();
            String[] numbers = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};
            StringBuffer code = new StringBuffer();
            int index = 0;
            // 创建验证码
            while (index < 6) {
                int number = r.nextInt(10);
                code.append(numbers[number]);
                index++;
            }

            System.out.println(code);
            // 阿里云客户端发送验证码
            String smsCode = wdAliyunClient.sendSms(mobile, code);
            // 创建redis
            SmsVerificationService redisService = new SmsVerificationService();
            // 将验证码保存到redis
            redisService.generateVerificationCode(mobile, String.valueOf(code));
            return BaseRespVo.ok(null);

        } else {
            System.out.println("The phone number is invalid.");
            return BaseRespVo.fail("手机号不合法", 705);
        }
    }

    @PostMapping("/register")
    public BaseRespVo register(@RequestBody Map<String, String> map, HttpServletRequest request) {
        String password = map.get("password");
        String username = map.get("username");
        String code = map.get("code");
        String mobile = map.get("mobile");
        // 创建redis服务对象
        SmsVerificationService redisService = new SmsVerificationService();
        // 对mobile对应的验证码进行验证，并删除验证正确后的验证码
        boolean phoneIsExist = userService.phoneExist(mobile);
        if (!phoneIsExist) {
            return BaseRespVo.fail("手机号已经注册", 704);
        }

        boolean userIsExist = userService.userNameExist(username);
        if (!userIsExist) {
            return BaseRespVo.fail("用户名已注册", 704);
        }

        boolean verify = redisService.verifyVerificationCode(mobile, code);
        if (!verify) {
            return BaseRespVo.fail("验证码不正确", 705);
        }


        String remoteAddr = request.getRemoteAddr();
        // 保存用户注册的信息
        RegisterData registerData = userService.addNewUser(username, password, mobile, remoteAddr);

        //将加密后的密码添加到subject里
        String md5Password = MD5Util.getMd5(password);

        // 1. subject表示当前用户（基于Shiro的Session会话技术）
        Subject subject = SecurityUtils.getSubject();
        subject.login(new UsernamePasswordToken(username, md5Password));
        // 3.1 data中token
        Serializable token = subject.getSession().getId();

        registerData.setToken((String) token);

        return BaseRespVo.ok(registerData);
    }

    // 3. 用户登出
    @PostMapping("logout")
    public BaseRespVo logout() {
        return BaseRespVo.ok(null);
    }

    @PostMapping("/reset")
    public BaseRespVo reset(@RequestBody Map<String, String> map, HttpServletRequest request) {
        String code = map.get("code");
        String mobile = map.get("mobile");
        String password = map.get("password");
        String remoteAddr = request.getRemoteAddr();
        // 判断手机号注册了吗
        boolean phoneIsExist = userService.phoneExist(mobile);
        if (phoneIsExist) {
            return BaseRespVo.fail("该用户还没注册", 704);
        }
        // 验证手机验证码
        SmsVerificationService redisService = new SmsVerificationService();
        boolean verify = redisService.verifyVerificationCode(mobile, code);
        if (!verify) {
            return BaseRespVo.fail("验证码不正确", 705);
        }

        userService.resetPassword(mobile, password, remoteAddr);

        return BaseRespVo.ok(null);
    }
}
